home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
- The Netherlands.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the names of Stichting Mathematisch
- Centrum or CWI or Corporation for National Research Initiatives or
- CNRI not be used in advertising or publicity pertaining to
- distribution of the software without specific, written prior
- permission.
-
- While CWI is the initial source for this software, a modified version
- is made available by the Corporation for National Research Initiatives
- (CNRI) at the Internet address ftp://ftp.python.org.
-
- STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
- CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-
- ******************************************************************/
-
- /* Long (arbitrary precision) integer object implementation */
-
- /* XXX The functional organization of this file is terrible */
-
- #include "allobjects.h"
- #include "longintrepr.h"
- #include "mymath.h"
- #include <assert.h>
- #include <ctype.h>
-
- #define ABS(x) ((x) < 0 ? -(x) : (x))
-
- /* Forward */
- #include "protos/longobject_protos.h"
- static longobject *long_normalize PROTO((longobject *));
- static longobject *mul1 PROTO((longobject *, wdigit));
- static longobject *muladd1 PROTO((longobject *, wdigit, wdigit));
- static longobject *divrem1 PROTO((longobject *, wdigit, digit *));
- static object *long_format PROTO((object *aa, int base));
-
- static int ticker; /* XXX Could be shared with ceval? */
-
- #define SIGCHECK(block) \
- if (--ticker < 0) { \
- ticker = 100; \
- if (sigcheck()) { block; } \
- }
-
- /* Normalize (remove leading zeros from) a long int object.
- Doesn't attempt to free the storage--in most cases, due to the nature
- of the algorithms used, this could save at most be one word anyway. */
-
- static longobject *
- long_normalize(v)
- register longobject *v;
- {
- int j = ABS(v->ob_size);
- register int i = j;
-
- while (i > 0 && v->ob_digit[i-1] == 0)
- --i;
- if (i != j)
- v->ob_size = (v->ob_size < 0) ? -(i) : i;
- return v;
- }
-
- /* Allocate a new long int object with size digits.
- Return NULL and set exception if we run out of memory. */
-
- longobject *
- alloclongobject(size)
- int size;
- {
- return NEWVAROBJ(longobject, &Longtype, size);
- }
-
- /* Create a new long int object from a C long int */
-
- object *
- newlongobject(ival)
- long ival;
- {
- /* Assume a C long fits in at most 3 'digits' */
- /* XXX On 64 bit machines this isn't true!!! */
- longobject *v = alloclongobject(3);
- if (v != NULL) {
- if (ival < 0) {
- ival = -ival;
- v->ob_size = -(v->ob_size);
- }
- v->ob_digit[0] = ival & MASK;
- v->ob_digit[1] = (ival >> SHIFT) & MASK;
- v->ob_digit[2] = ((unsigned long)ival >> (2*SHIFT)) & MASK;
- v = long_normalize(v);
- }
- return (object *)v;
- }
-
- /* Create a new long int object from a C double */
-
- object *
- #ifdef MPW
- dnewlongobject(double dval)
- #else
- dnewlongobject(dval)
- double dval;
- #endif /* MPW */
- {
- longobject *v;
- double frac;
- int i, ndig, expo, neg;
- neg = 0;
- if (dval < 0.0) {
- neg = 1;
- dval = -dval;
- }
- frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */
-
- if (expo <= 0)
- return newlongobject(0L);
- ndig = (expo-1) / SHIFT + 1; /* Number of 'digits' in result */
- v = alloclongobject(ndig);
- if (v == NULL)
- return NULL;
- frac = ldexp(frac, (expo-1) % SHIFT + 1);
- for (i = ndig; --i >= 0; ) {
- long bits = (long)frac;
- v->ob_digit[i] = bits;
- frac = frac - (double)bits;
- frac = ldexp(frac, SHIFT);
- }
- if (neg)
- v->ob_size = -(v->ob_size);
- return (object *)v;
- }
-
- /* Get a C long int from a long int object.
- Returns -1 and sets an error condition if overflow occurs. */
-
- long
- getlongvalue(vv)
- object *vv;
- {
- register longobject *v;
- long x, prev;
- int i, sign;
-
- if (vv == NULL || !is_longobject(vv)) {
- err_badcall();
- return -1;
- }
- v = (longobject *)vv;
- i = v->ob_size;
- sign = 1;
- x = 0;
- if (i < 0) {
- sign = -1;
- i = -(i);
- }
- while (--i >= 0) {
- prev = x;
- x = (x << SHIFT) + v->ob_digit[i];
- if ((x >> SHIFT) != prev) {
- err_setstr(OverflowError,
- "long int too long to convert");
- return -1;
- }
- }
- return x * sign;
- }
-
- /* Get a C double from a long int object. No overflow check. */
-
- double
- dgetlongvalue(vv)
- object *vv;
- {
- register longobject *v;
- double x;
- double multiplier = (double) (1L << SHIFT);
- int i, sign;
-
- if (vv == NULL || !is_longobject(vv)) {
- err_badcall();
- return -1;
- }
- v = (longobject *)vv;
- i = v->ob_size;
- sign = 1;
- x = 0.0;
- if (i < 0) {
- sign = -1;
- i = -(i);
- }
- while (--i >= 0) {
- x = x*multiplier + (double)v->ob_digit[i];
- }
- return x * sign;
- }
-
- /* Multiply by a single digit, ignoring the sign. */
-
- static longobject *
- mul1(a, n)
- longobject *a;
- wdigit n;
- {
- return muladd1(a, n, (digit)0);
- }
-
- /* Multiply by a single digit and add a single digit, ignoring the sign. */
-
- static longobject *
- muladd1(a, n, extra)
- longobject *a;
- wdigit n;
- wdigit extra;
- {
- int size_a = ABS(a->ob_size);
- longobject *z = alloclongobject(size_a+1);
- twodigits carry = extra;
- int i;
-
- if (z == NULL)
- return NULL;
- for (i = 0; i < size_a; ++i) {
- carry += (twodigits)a->ob_digit[i] * n;
- z->ob_digit[i] = carry & MASK;
- carry >>= SHIFT;
- }
- z->ob_digit[i] = carry;
- return long_normalize(z);
- }
-
- /* Divide a long integer by a digit, returning both the quotient
- (as function result) and the remainder (through *prem).
- The sign of a is ignored; n should not be zero. */
-
- static longobject *
- divrem1(a, n, prem)
- longobject *a;
- wdigit n;
- digit *prem;
- {
- int size = ABS(a->ob_size);
- longobject *z;
- int i;
- twodigits rem = 0;
-
- assert(n > 0 && n <= MASK);
- z = alloclongobject(size);
- if (z == NULL)
- return NULL;
- for (i = size; --i >= 0; ) {
- rem = (rem << SHIFT) + a->ob_digit[i];
- z->ob_digit[i] = rem/n;
- rem %= n;
- }
- *prem = rem;
- return long_normalize(z);
- }
-
- /* Convert a long int object to a string, using a given conversion base.
- Return a string object.
- If base is 8 or 16, add the proper prefix '0' or '0x'.
- External linkage: used in bltinmodule.c by hex() and oct(). */
-
- static object *
- long_format(aa, base)
- object *aa;
- int base;
- {
- register longobject *a = (longobject *)aa;
- stringobject *str;
- int i;
- int size_a = ABS(a->ob_size);
- char *p;
- int bits;
- char sign = '\0';
-
- if (a == NULL || !is_longobject(a)) {
- err_badcall();
- return NULL;
- }
- assert(base >= 2 && base <= 36);
-
- /* Compute a rough upper bound for the length of the string */
- i = base;
- bits = 0;
- while (i > 1) {
- ++bits;
- i >>= 1;
- }
- i = 6 + (size_a*SHIFT + bits-1) / bits;
- str = (stringobject *) newsizedstringobject((char *)0, i);
- if (str == NULL)
- return NULL;
- p = GETSTRINGVALUE(str) + i;
- *p = '\0';
- *--p = 'L';
- if (a->ob_size < 0)
- sign = '-';
-
- INCREF(a);
- do {
- digit rem;
- longobject *temp = divrem1(a, (digit)base, &rem);
- if (temp == NULL) {
- DECREF(a);
- DECREF(str);
- return NULL;
- }
- if (rem < 10)
- rem += '0';
- else
- rem += 'A'-10;
- assert(p > GETSTRINGVALUE(str));
- *--p = rem;
- DECREF(a);
- a = temp;
- SIGCHECK({
- DECREF(a);
- DECREF(str);
- return NULL;
- })
- } while (ABS(a->ob_size) != 0);
- DECREF(a);
- if (base == 8) {
- if (size_a != 0)
- *--p = '0';
- }
- else if (base == 16) {
- *--p = 'x';
- *--p = '0';
- }
- else if (base != 10) {
- *--p = '#';
- *--p = '0' + base%10;
- if (base > 10)
- *--p = '0' + base/10;
- }
- if (sign)
- *--p = sign;
- if (p != GETSTRINGVALUE(str)) {
- char *q = GETSTRINGVALUE(str);
- assert(p > q);
- do {
- } while ((*q++ = *p++) != '\0');
- q--;
- resizestring((object **)&str, (int) (q - GETSTRINGVALUE(str)));
- }
- return (object *)str;
- }
-
- #if 0
- /* Convert a string to a long int object, in a given base.
- Base zero implies a default depending on the number.
- External linkage: used in compile.c and stropmodule.c. */
-
- object *
- long_scan(str, base)
- char *str;
- int base;
- {
- return long_escan(str, (char **)NULL, base);
- }
- #endif
-
- object *
- long_escan(str, pend, base)
- char *str;
- char **pend;
- int base;
- {
- int sign = 1;
- longobject *z;
-
- if (base != 0 && base < 2 || base > 36) {
- err_setstr(ValueError, "invalid base for long literal");
- return NULL;
- }
- while (*str != '\0' && isspace(Py_CHARMASK(*str)))
- str++;
- if (*str == '+')
- ++str;
- else if (*str == '-') {
- ++str;
- sign = -1;
- }
- while (*str != '\0' && isspace(Py_CHARMASK(*str)))
- str++;
- if (base == 0) {
- if (str[0] != '0')
- base = 10;
- else if (str[1] == 'x' || str[1] == 'X')
- base = 16;
- else
- base = 8;
- }
- if (base == 16 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
- str += 2;
- z = alloclongobject(0);
- for ( ; z != NULL; ++str) {
- int k = -1;
- longobject *temp;
-
- if (*str <= '9')
- k = *str - '0';
- else if (*str >= 'a')
- k = *str - 'a' + 10;
- else if (*str >= 'A')
- k = *str - 'A' + 10;
- if (k < 0 || k >= base)
- break;
- temp = muladd1(z, (digit)base, (digit)k);
- DECREF(z);
- z = temp;
- }
- if (sign < 0 && z != NULL && z->ob_size != 0)
- z->ob_size = -(z->ob_size);
- if (pend)
- *pend = str;
- return (object *) z;
- }
-
- static longobject *x_divrem PROTO((longobject *, longobject *, longobject **));
- static object *long_pos PROTO((longobject *));
- static long_divrem PROTO((longobject *, longobject *,
- longobject **, longobject **));
-
- /* Long division with remainder, top-level routine */
-
- static int
- long_divrem(a, b, pdiv, prem)
- longobject *a, *b;
- longobject **pdiv;
- longobject **prem;
- {
- int size_a = ABS(a->ob_size), size_b = ABS(b->ob_size);
- longobject *z;
-
- if (size_b == 0) {
- err_setstr(ZeroDivisionError, "long division or modulo");
- return -1;
- }
- if (size_a < size_b ||
- size_a == size_b &&
- a->ob_digit[size_a-1] < b->ob_digit[size_b-1]) {
- /* |a| < |b|. */
- *pdiv = alloclongobject(0);
- INCREF(a);
- *prem = (longobject *) a;
- return 0;
- }
- if (size_b == 1) {
- digit rem = 0;
- z = divrem1(a, b->ob_digit[0], &rem);
- if (z == NULL)
- return -1;
- *prem = (longobject *) newlongobject((long)rem);
- }
- else {
- z = x_divrem(a, b, prem);
- if (z == NULL)
- return -1;
- }
- /* Set the signs.
- The quotient z has the sign of a*b;
- the remainder r has the sign of a,
- so a = b*z + r. */
- if ((a->ob_size < 0) != (b->ob_size < 0))
- z->ob_size = -(z->ob_size);
- if (a->ob_size < 0 && (*prem)->ob_size != 0)
- (*prem)->ob_size = -((*prem)->ob_size);
- *pdiv = z;
- return 0;
- }
-
- /* Unsigned long division with remainder -- the algorithm */
-
- static longobject *
- x_divrem(v1, w1, prem)
- longobject *v1, *w1;
- longobject **prem;
- {
- int size_v = ABS(v1->ob_size), size_w = ABS(w1->ob_size);
- digit d = (twodigits)BASE / (w1->ob_digit[size_w-1] + 1);
- longobject *v = mul1(v1, d);
- longobject *w = mul1(w1, d);
- longobject *a;
- int j, k;
-
- if (v == NULL || w == NULL) {
- XDECREF(v);
- XDECREF(w);
- return NULL;
- }
-
- assert(size_v >= size_w && size_w > 1); /* Assert checks by div() */
- assert(v->ob_refcnt == 1); /* Since v will be used as accumulator! */
- assert(size_w == ABS(w->ob_size)); /* That's how d was calculated */
-
- size_v = ABS(v->ob_size);
- a = alloclongobject(size_v - size_w + 1);
-
- for (j = size_v, k = a->ob_size-1; a != NULL && k >= 0; --j, --k) {
- digit vj = (j >= size_v) ? 0 : v->ob_digit[j];
- twodigits q;
- stwodigits carry = 0;
- int i;
-
- SIGCHECK({
- DECREF(a);
- a = NULL;
- break;
- })
- if (vj == w->ob_digit[size_w-1])
- q = MASK;
- else
- q = (((twodigits)vj << SHIFT) + v->ob_digit[j-1]) /
- w->ob_digit[size_w-1];
-
- while (w->ob_digit[size_w-2]*q >
- ((
- ((twodigits)vj << SHIFT)
- + v->ob_digit[j-1]
- - q*w->ob_digit[size_w-1]
- ) << SHIFT)
- + v->ob_digit[j-2])
- --q;
-
- for (i = 0; i < size_w && i+k < size_v; ++i) {
- twodigits z = w->ob_digit[i] * q;
- digit zz = z >> SHIFT;
- carry += v->ob_digit[i+k] - z + ((twodigits)zz << SHIFT);
- v->ob_digit[i+k] = carry & MASK;
- carry = (carry >> SHIFT) - zz;
- }
-
- if (i+k < size_v) {
- carry += v->ob_digit[i+k];
- v->ob_digit[i+k] = 0;
- }
-
- if (carry == 0)
- a->ob_digit[k] = q;
- else {
- assert(carry == -1);
- a->ob_digit[k] = q-1;
- carry = 0;
- for (i = 0; i < size_w && i+k < size_v; ++i) {
- carry += v->ob_digit[i+k] + w->ob_digit[i];
- v->ob_digit[i+k] = carry & MASK;
- carry >>= SHIFT;
- }
- }
- } /* for j, k */
-
- if (a == NULL)
- *prem = NULL;
- else {
- a = long_normalize(a);
- *prem = divrem1(v, d, &d);
- /* d receives the (unused) remainder */
- if (*prem == NULL) {
- DECREF(a);
- a = NULL;
- }
- }
- DECREF(v);
- DECREF(w);
- return a;
- }
-
- /* Methods */
-
- /* Forward */
- static void long_dealloc PROTO((object *));
- static object *long_repr PROTO((object *));
- static int long_compare PROTO((longobject *, longobject *));
- static long long_hash PROTO((longobject *));
-
- static object *long_add PROTO((longobject *, longobject *));
- static object *long_sub PROTO((longobject *, longobject *));
- static object *long_mul PROTO((longobject *, longobject *));
- static object *long_div PROTO((longobject *, longobject *));
- static object *long_mod PROTO((longobject *, longobject *));
- static object *long_divmod PROTO((longobject *, longobject *));
- static object *long_pow PROTO((longobject *, longobject *, longobject *));
- static object *long_neg PROTO((longobject *));
- static object *long_pos PROTO((longobject *));
- static object *long_abs PROTO((longobject *));
- static int long_nonzero PROTO((longobject *));
- static object *long_invert PROTO((longobject *));
- static object *long_lshift PROTO((longobject *, longobject *));
- static object *long_rshift PROTO((longobject *, longobject *));
- static object *long_and PROTO((longobject *, longobject *));
- static object *long_xor PROTO((longobject *, longobject *));
- static object *long_or PROTO((longobject *, longobject *));
-
- static void
- long_dealloc(v)
- object *v;
- {
- DEL(v);
- }
-
- static object *
- long_repr(v)
- object *v;
- {
- return long_format(v, 10);
- }
-
- static int
- long_compare(a, b)
- longobject *a, *b;
- {
- int sign;
-
- if (a->ob_size != b->ob_size) {
- if (ABS(a->ob_size) == 0 && ABS(b->ob_size) == 0)
- sign = 0;
- else
- sign = a->ob_size - b->ob_size;
- }
- else {
- int i = ABS(a->ob_size);
- while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
- ;
- if (i < 0)
- sign = 0;
- else {
- sign = (int)a->ob_digit[i] - (int)b->ob_digit[i];
- if (a->ob_size < 0)
- sign = -sign;
- }
- }
- return sign < 0 ? -1 : sign > 0 ? 1 : 0;
- }
-
- static long
- long_hash(v)
- longobject *v;
- {
- long x;
- int i, sign;
-
- /* This is designed so that Python ints and longs with the
- same value hash to the same value, otherwise comparisons
- of mapping keys will turn out weird */
- i = v->ob_size;
- sign = 1;
- x = 0;
- if (i < 0) {
- sign = -1;
- i = -(i);
- }
- while (--i >= 0) {
- /* Force a 32-bit circular shift */
- x = ((x << SHIFT) & ~MASK) | ((x >> (32-SHIFT)) & MASK);
- x += v->ob_digit[i];
- }
- x = x * sign;
- if (x == -1)
- x = -2;
- return x;
- }
-
-
- /* Add the absolute values of two long integers. */
-
- static longobject *x_add PROTO((longobject *, longobject *));
- static longobject *
- x_add(a, b)
- longobject *a, *b;
- {
- int size_a = ABS(a->ob_size), size_b = ABS(b->ob_size);
- longobject *z;
- int i;
- digit carry = 0;
-
- /* Ensure a is the larger of the two: */
- if (size_a < size_b) {
- { longobject *temp = a; a = b; b = temp; }
- { int size_temp = size_a; size_a = size_b; size_b = size_temp; }
- }
- z = alloclongobject(size_a+1);
- if (z == NULL)
- return NULL;
- for (i = 0; i < size_b; ++i) {
- carry += a->ob_digit[i] + b->ob_digit[i];
- z->ob_digit[i] = carry & MASK;
- /* The following assumes unsigned shifts don't
- propagate the sign bit. */
- carry >>= SHIFT;
- }
- for (; i < size_a; ++i) {
- carry += a->ob_digit[i];
- z->ob_digit[i] = carry & MASK;
- carry >>= SHIFT;
- }
- z->ob_digit[i] = carry;
- return long_normalize(z);
- }
-
- /* Subtract the absolute values of two integers. */
-
- static longobject *x_sub PROTO((longobject *, longobject *));
- static longobject *
- x_sub(a, b)
- longobject *a, *b;
- {
- int size_a = ABS(a->ob_size), size_b = ABS(b->ob_size);
- longobject *z;
- int i;
- int sign = 1;
- digit borrow = 0;
-
- /* Ensure a is the larger of the two: */
- if (size_a < size_b) {
- sign = -1;
- { longobject *temp = a; a = b; b = temp; }
- { int size_temp = size_a; size_a = size_b; size_b = size_temp; }
- }
- else if (size_a == size_b) {
- /* Find highest digit where a and b differ: */
- i = size_a;
- while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i])
- ;
- if (i < 0)
- return alloclongobject(0);
- if (a->ob_digit[i] < b->ob_digit[i]) {
- sign = -1;
- { longobject *temp = a; a = b; b = temp; }
- }
- size_a = size_b = i+1;
- }
- z = alloclongobject(size_a);
- if (z == NULL)
- return NULL;
- for (i = 0; i < size_b; ++i) {
- /* The following assumes unsigned arithmetic
- works module 2**N for some N>SHIFT. */
- borrow = a->ob_digit[i] - b->ob_digit[i] - borrow;
- z->ob_digit[i] = borrow & MASK;
- borrow >>= SHIFT;
- borrow &= 1; /* Keep only one sign bit */
- }
- for (; i < size_a; ++i) {
- borrow = a->ob_digit[i] - borrow;
- z->ob_digit[i] = borrow & MASK;
- borrow >>= SHIFT;
- }
- assert(borrow == 0);
- if (sign < 0)
- z->ob_size = -(z->ob_size);
- return long_normalize(z);
- }
-
- static object *
- long_add(a, b)
- longobject *a;
- longobject *b;
- {
- longobject *z;
-
- if (a->ob_size < 0) {
- if (b->ob_size < 0) {
- z = x_add(a, b);
- if (z != NULL && z->ob_size != 0)
- z->ob_size = -(z->ob_size);
- }
- else
- z = x_sub(b, a);
- }
- else {
- if (b->ob_size < 0)
- z = x_sub(a, b);
- else
- z = x_add(a, b);
- }
- return (object *)z;
- }
-
- static object *
- long_sub(a, b)
- longobject *a;
- longobject *b;
- {
- longobject *z;
-
- if (a->ob_size < 0) {
- if (b->ob_size < 0)
- z = x_sub(a, b);
- else
- z = x_add(a, b);
- if (z != NULL && z->ob_size != 0)
- z->ob_size = -(z->ob_size);
- }
- else {
- if (b->ob_size < 0)
- z = x_add(a, b);
- else
- z = x_sub(a, b);
- }
- return (object *)z;
- }
-
- static object *
- long_mul(a, b)
- longobject *a;
- longobject *b;
- {
- int size_a;
- int size_b;
- longobject *z;
- int i;
-
- size_a = ABS(a->ob_size);
- size_b = ABS(b->ob_size);
- z = alloclongobject(size_a + size_b);
- if (z == NULL)
- return NULL;
- for (i = 0; i < z->ob_size; ++i)
- z->ob_digit[i] = 0;
- for (i = 0; i < size_a; ++i) {
- twodigits carry = 0;
- twodigits f = a->ob_digit[i];
- int j;
-
- SIGCHECK({
- DECREF(z);
- return NULL;
- })
- for (j = 0; j < size_b; ++j) {
- carry += z->ob_digit[i+j] + b->ob_digit[j] * f;
- z->ob_digit[i+j] = carry & MASK;
- carry >>= SHIFT;
- }
- for (; carry != 0; ++j) {
- assert(i+j < z->ob_size);
- carry += z->ob_digit[i+j];
- z->ob_digit[i+j] = carry & MASK;
- carry >>= SHIFT;
- }
- }
- if (a->ob_size < 0)
- z->ob_size = -(z->ob_size);
- if (b->ob_size < 0)
- z->ob_size = -(z->ob_size);
- return (object *) long_normalize(z);
- }
-
- /* The / and % operators are now defined in terms of divmod().
- The expression a mod b has the value a - b*floor(a/b).
- The long_divrem function gives the remainder after division of
- |a| by |b|, with the sign of a. This is also expressed
- as a - b*trunc(a/b), if trunc truncates towards zero.
- Some examples:
- a b a rem b a mod b
- 13 10 3 3
- -13 10 -3 7
- 13 -10 3 -7
- -13 -10 -3 -3
- So, to get from rem to mod, we have to add b if a and b
- have different signs. We then subtract one from the 'div'
- part of the outcome to keep the invariant intact. */
-
- static int l_divmod PROTO((longobject *, longobject *,
- longobject **, longobject **));
- static int
- l_divmod(v, w, pdiv, pmod)
- longobject *v;
- longobject *w;
- longobject **pdiv;
- longobject **pmod;
- {
- longobject *div, *mod;
-
- if (long_divrem(v, w, &div, &mod) < 0)
- return -1;
- if (mod->ob_size < 0 && w->ob_size > 0 ||
- mod->ob_size > 0 && w->ob_size < 0) {
- longobject *temp;
- longobject *one;
- temp = (longobject *) long_add(mod, w);
- DECREF(mod);
- mod = temp;
- if (mod == NULL) {
- DECREF(div);
- return -1;
- }
- one = (longobject *) newlongobject(1L);
- if (one == NULL ||
- (temp = (longobject *) long_sub(div, one)) == NULL) {
- DECREF(mod);
- DECREF(div);
- XDECREF(one);
- return -1;
- }
- DECREF(one);
- DECREF(div);
- div = temp;
- }
- *pdiv = div;
- *pmod = mod;
- return 0;
- }
-
- static object *
- long_div(v, w)
- longobject *v;
- longobject *w;
- {
- longobject *div, *mod;
- if (l_divmod(v, w, &div, &mod) < 0)
- return NULL;
- DECREF(mod);
- return (object *)div;
- }
-
- static object *
- long_mod(v, w)
- longobject *v;
- longobject *w;
- {
- longobject *div, *mod;
- if (l_divmod(v, w, &div, &mod) < 0)
- return NULL;
- DECREF(div);
- return (object *)mod;
- }
-
- static object *
- long_divmod(v, w)
- longobject *v;
- longobject *w;
- {
- object *z;
- longobject *div, *mod;
- if (l_divmod(v, w, &div, &mod) < 0)
- return NULL;
- z = newtupleobject(2);
- if (z != NULL) {
- settupleitem(z, 0, (object *) div);
- settupleitem(z, 1, (object *) mod);
- }
- else {
- DECREF(div);
- DECREF(mod);
- }
- return z;
- }
-
- static object *
- long_pow(a, b, c)
- longobject *a;
- longobject *b;
- longobject *c;
- {
- longobject *z, *div, *mod;
- int size_b, i;
-
- size_b = b->ob_size;
- if (size_b < 0) {
- err_setstr(ValueError, "long integer to the negative power");
- return NULL;
- }
- z = (longobject *)newlongobject(1L);
- INCREF(a);
- for (i = 0; i < size_b; ++i) {
- digit bi = b->ob_digit[i];
- int j;
-
- for (j = 0; j < SHIFT; ++j) {
- longobject *temp;
-
- if (bi & 1) {
- temp = (longobject *)long_mul(z, a);
- DECREF(z);
- if ((object*)c!=None && temp!=NULL) {
- l_divmod(temp, c, &div, &mod);
- XDECREF(div);
- DECREF(temp);
- temp = mod;
- }
- z = temp;
- if (z == NULL)
- break;
- }
- bi >>= 1;
- if (bi == 0 && i+1 == size_b)
- break;
- temp = (longobject *)long_mul(a, a);
- DECREF(a);
- if ((object*)c!=None && temp!=NULL) {
- l_divmod(temp, c, &div, &mod);
- XDECREF(div);
- DECREF(temp);
- temp = mod;
- }
- a = temp;
- if (a == NULL) {
- DECREF(z);
- z = NULL;
- break;
- }
- }
- if (a == NULL || z == NULL)
- break;
- }
- XDECREF(a);
- if ((object*)c!=None && z!=NULL) {
- l_divmod(z, c, &div, &mod);
- XDECREF(div);
- DECREF(z);
- z=mod;
- }
- return (object *)z;
- }
-
- static object *
- long_invert(v)
- longobject *v;
- {
- /* Implement ~x as -(x+1) */
- longobject *x;
- longobject *w;
- w = (longobject *)newlongobject(1L);
- if (w == NULL)
- return NULL;
- x = (longobject *) long_add(v, w);
- DECREF(w);
- if (x == NULL)
- return NULL;
- if (x->ob_size != 0)
- x->ob_size = -(x->ob_size);
- return (object *)x;
- }
-
- static object *
- long_pos(v)
- longobject *v;
- {
- INCREF(v);
- return (object *)v;
- }
-
- static object *
- long_neg(v)
- longobject *v;
- {
- longobject *z;
- int i, n;
- n = ABS(v->ob_size);
- if (n == 0) {
- /* -0 == 0 */
- INCREF(v);
- return (object *) v;
- }
- z = alloclongobject(ABS(n));
- if (z == NULL)
- return NULL;
- for (i = 0; i < n; i++)
- z->ob_digit[i] = v->ob_digit[i];
- z->ob_size = -(v->ob_size);
- return (object *)z;
- }
-
- static object *
- long_abs(v)
- longobject *v;
- {
- if (v->ob_size < 0)
- return long_neg(v);
- else {
- INCREF(v);
- return (object *)v;
- }
- }
-
- static int
- long_nonzero(v)
- longobject *v;
- {
- return ABS(v->ob_size) != 0;
- }
-
- static object *
- long_rshift(a, b)
- longobject *a;
- longobject *b;
- {
- longobject *z;
- long shiftby;
- int newsize, wordshift, loshift, hishift, i, j;
- digit lomask, himask;
-
- if (a->ob_size < 0) {
- /* Right shifting negative numbers is harder */
- longobject *a1, *a2, *a3;
- a1 = (longobject *) long_invert(a);
- if (a1 == NULL) return NULL;
- a2 = (longobject *) long_rshift(a1, b);
- DECREF(a1);
- if (a2 == NULL) return NULL;
- a3 = (longobject *) long_invert(a2);
- DECREF(a2);
- return (object *) a3;
- }
-
- shiftby = getlongvalue((object *)b);
- if (shiftby == -1L && err_occurred())
- return NULL;
- if (shiftby < 0) {
- err_setstr(ValueError, "negative shift count");
- return NULL;
- }
- wordshift = shiftby / SHIFT;
- newsize = ABS(a->ob_size) - wordshift;
- if (newsize <= 0) {
- z = alloclongobject(0);
- return (object *)z;
- }
- loshift = shiftby % SHIFT;
- hishift = SHIFT - loshift;
- lomask = ((digit)1 << hishift) - 1;
- himask = MASK ^ lomask;
- z = alloclongobject(newsize);
- if (z == NULL)
- return NULL;
- if (a->ob_size < 0)
- z->ob_size = -(z->ob_size);
- for (i = 0, j = wordshift; i < newsize; i++, j++) {
- z->ob_digit[i] = (a->ob_digit[j] >> loshift) & lomask;
- if (i+1 < newsize)
- z->ob_digit[i] |=
- (a->ob_digit[j+1] << hishift) & himask;
- }
- return (object *) long_normalize(z);
- }
-
- static object *
- long_lshift(a, b)
- longobject *a;
- longobject *b;
- {
- longobject *z;
- long shiftby;
- int newsize, wordshift, loshift, hishift, i, j;
- digit lomask, himask;
-
- shiftby = getlongvalue((object *)b);
- if (shiftby == -1L && err_occurred())
- return NULL;
- if (shiftby < 0) {
- err_setstr(ValueError, "negative shift count");
- return NULL;
- }
- if (shiftby > MASK) {
- err_setstr(ValueError, "outrageous left shift count");
- return NULL;
- }
- if (shiftby % SHIFT == 0) {
- wordshift = shiftby / SHIFT;
- loshift = 0;
- hishift = SHIFT;
- newsize = ABS(a->ob_size) + wordshift;
- lomask = MASK;
- himask = 0;
- }
- else {
- wordshift = shiftby / SHIFT + 1;
- loshift = SHIFT - shiftby%SHIFT;
- hishift = shiftby % SHIFT;
- newsize = ABS(a->ob_size) + wordshift;
- lomask = ((digit)1 << hishift) - 1;
- himask = MASK ^ lomask;
- }
- z = alloclongobject(newsize);
- if (z == NULL)
- return NULL;
- if (a->ob_size < 0)
- z->ob_size = -(z->ob_size);
- for (i = 0; i < wordshift; i++)
- z->ob_digit[i] = 0;
- for (i = wordshift, j = 0; i < newsize; i++, j++) {
- if (i > 0)
- z->ob_digit[i-1] |=
- (a->ob_digit[j] << hishift) & himask;
- z->ob_digit[i] =
- (a->ob_digit[j] >> loshift) & lomask;
- }
- return (object *) long_normalize(z);
- }
-
-
- /* Bitwise and/xor/or operations */
-
- #define MAX(x, y) ((x) < (y) ? (y) : (x))
- #define MIN(x, y) ((x) > (y) ? (y) : (x))
-
- static object *long_bitwise PROTO((longobject *, int, longobject *));
- static object *
- long_bitwise(a, op, b)
- longobject *a;
- int op; /* '&', '|', '^' */
- longobject *b;
- {
- digit maska, maskb; /* 0 or MASK */
- int negz;
- int size_a, size_b, size_z;
- longobject *z;
- int i;
- digit diga, digb;
- object *v;
-
- if (a->ob_size < 0) {
- a = (longobject *) long_invert(a);
- maska = MASK;
- }
- else {
- INCREF(a);
- maska = 0;
- }
- if (b->ob_size < 0) {
- b = (longobject *) long_invert(b);
- maskb = MASK;
- }
- else {
- INCREF(b);
- maskb = 0;
- }
-
- size_a = a->ob_size;
- size_b = b->ob_size;
- size_z = MAX(size_a, size_b);
- z = alloclongobject(size_z);
- if (a == NULL || b == NULL || z == NULL) {
- XDECREF(a);
- XDECREF(b);
- XDECREF(z);
- return NULL;
- }
-
- negz = 0;
- switch (op) {
- case '^':
- if (maska != maskb) {
- maska ^= MASK;
- negz = -1;
- }
- break;
- case '&':
- if (maska && maskb) {
- op = '|';
- maska ^= MASK;
- maskb ^= MASK;
- negz = -1;
- }
- break;
- case '|':
- if (maska || maskb) {
- op = '&';
- maska ^= MASK;
- maskb ^= MASK;
- negz = -1;
- }
- break;
- }
-
- for (i = 0; i < size_z; ++i) {
- diga = (i < size_a ? a->ob_digit[i] : 0) ^ maska;
- digb = (i < size_b ? b->ob_digit[i] : 0) ^ maskb;
- switch (op) {
- case '&': z->ob_digit[i] = diga & digb; break;
- case '|': z->ob_digit[i] = diga | digb; break;
- case '^': z->ob_digit[i] = diga ^ digb; break;
- }
- }
-
- DECREF(a);
- DECREF(b);
- z = long_normalize(z);
- if (negz == 0)
- return (object *) z;
- v = long_invert(z);
- DECREF(z);
- return v;
- }
-
- static object *
- long_and(a, b)
- longobject *a;
- longobject *b;
- {
- return long_bitwise(a, '&', b);
- }
-
- static object *
- long_xor(a, b)
- longobject *a;
- longobject *b;
- {
- return long_bitwise(a, '^', b);
- }
-
- static object *
- long_or(a, b)
- longobject *a;
- longobject *b;
- {
- return long_bitwise(a, '|', b);
- }
-
- static int
- long_coerce(pv, pw)
- object **pv;
- object **pw;
- {
- if (is_intobject(*pw)) {
- *pw = newlongobject(getintvalue(*pw));
- INCREF(*pv);
- return 0;
- }
- return 1; /* Can't do it */
- }
-
- static object *
- long_int(v)
- object *v;
- {
- long x;
- x = getlongvalue(v);
- if (err_occurred())
- return NULL;
- return newintobject(x);
- }
-
- static object *
- long_long(v)
- object *v;
- {
- INCREF(v);
- return v;
- }
-
- static object *
- long_float(v)
- object *v;
- {
- return newfloatobject(dgetlongvalue(v));
- }
-
- static object *
- long_oct(v)
- object *v;
- {
- return long_format(v, 8);
- }
-
- static object *
- long_hex(v)
- object *v;
- {
- return long_format(v, 16);
- }
-
-
- #define UF (unaryfunc)
- #define BF (binaryfunc)
- #define TF (ternaryfunc)
- #define IF (inquiry)
-
- static number_methods long_as_number = {
- BF long_add, /*nb_add*/
- BF long_sub, /*nb_subtract*/
- BF long_mul, /*nb_multiply*/
- BF long_div, /*nb_divide*/
- BF long_mod, /*nb_remainder*/
- BF long_divmod, /*nb_divmod*/
- TF long_pow, /*nb_power*/
- UF long_neg, /*nb_negative*/
- UF long_pos, /*tp_positive*/
- UF long_abs, /*tp_absolute*/
- IF long_nonzero,/*tp_nonzero*/
- UF long_invert, /*nb_invert*/
- BF long_lshift, /*nb_lshift*/
- BF long_rshift, /*nb_rshift*/
- BF long_and, /*nb_and*/
- BF long_xor, /*nb_xor*/
- BF long_or, /*nb_or*/
- (int (*) FPROTO((object **, object **)))
- (coercion)long_coerce, /*nb_coerce*/
- UF long_int, /*nb_int*/
- UF long_long, /*nb_long*/
- UF long_float, /*nb_float*/
- UF long_oct, /*nb_oct*/
- UF long_hex, /*nb_hex*/
- };
-
- typeobject Longtype = {
- OB_HEAD_INIT(&Typetype)
- 0,
- "long int",
- sizeof(longobject) - sizeof(digit),
- sizeof(digit),
- (destructor)long_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- (int (*) FPROTO((object *, object *)))
- (cmpfunc)long_compare, /*tp_compare*/
- (reprfunc)long_repr, /*tp_repr*/
- &long_as_number,/*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- (long (*) FPROTO((object *)))
- (hashfunc)long_hash, /*tp_hash*/
- };
-